﻿#ifndef _STORAGE_INTERFACE_H
#define _STORAGE_INTERFACE_H
#include <stdint.h>
#include "media_frame_hd.h"
#include <time.h>
#include "storage_callback.h"

#define MAX_CH_NUM   16

#define FRAME_SOURCE_LOCAL    0
#define FRAME_SOURCE_SHAREMEM 1
#define FRAME_SOURCE_SIMULATE 2

typedef struct _CH_CFG_
{
	uint32_t isEnable;      //使能开关
	uint16_t real_ch;       //真实物理通道
	uint8_t  stream_type;   //主子码流
	uint8_t  src_type;      //视频源类型  0 内置视频缓冲 1跨进程共享内存 2模拟数据源
	uint32_t cache_sz;      //模块内置视频缓存大小
	uint32_t rec_disk_bit;  //录像磁盘编号 -1 所有磁盘都用 0x01 只录像在第一个盘上面

}CH_CFG_T;

typedef struct _StorageConfig_
{
	int32_t  channelNum;	    //支持的录像通道数
	int32_t  diskNum;
	int32_t  manualRecBIT;     //全时录像开关,接位处理

	uint8_t  bCycleRec;		 //循环录像
	uint8_t  bPrepare;		 //是否开启预录像
	uint8_t  bDisableCache;  // 是否禁用内置音视频缓存
	uint8_t  scan_drv_no;   //开始扫描的磁盘号
	uint32_t bSupportEmmc;   //是否支持Emmc录像
	int32_t  nPerpareSecs;   //预录像最大5S，
	uint32_t sptClientNum;  //支持的客户数目
	//  缓存使用信息
		//主码流，次码流 流媒体缓存
	uint32_t main_media_cache;//内置流码流缓存
	//必须要的。
	uint32_t buf_sz_flush;  //磁盘对齐刷新的大小
	uint32_t buf_sz_replay; //回放的缓存
	uint32_t buf_sz_frame;  //帧缓存大小
	int32_t   bNoneMixAudio;	//读取录像时是否混合音频，帧头+视频+音频
	char      event_path[120];//事件文件产生目录，同时也可以在些目录中记录
	int       enc_svc_speed; //视频编码的跳帧模式 2x 4x 
	CH_CFG_T  ch_cfg[MAX_CH_NUM];// 
	char      device_sn[24];  //设备ID
}StorageConfig;

typedef struct _StorageSpaceInfo_
{
	uint32_t diskNum;          //磁盘个数
	uint32_t freeSpace;        //剩余空间
	uint32_t totalSpace;       //磁盘总大小
	uint32_t dataPercent;      //数据占用百分比s
}StorageSpaceInfo;

typedef enum _disk_bus_type_
{
	BUS_TYPE_SATA = 0,		//本地磁盘
	BUS_TYPE_ESATA = 1,		//可以支持热插拨的SATA接口
	BUS_TYPE_USB = 2,		//USB接口
	BUS_TYPE_MMC = 3,      //MMC TF card
	BUS_TYPE_NAS = 4,		//NAS
}DISK_BUS_TYPE;


typedef enum _playback_type_
{
	REPLAY_NULL = 0,					//未设置
	REPLAY_PAUSE,						//暂停
	REPLAY_STOP,						//停止

	REPLAY_NORMAL = 0x10,				//正常回放
	REPLAY_ONEFRAME = 0x20,				//单帧播放
	REPLAY_SLOW = 0x40,				//慢进 2, 4, 8, 16, 32
	REPLAY_FAST = 0x80,				//快进 2, 4, 8, 16, 32
	REPLAY_REBACK = 0x100,				//回退 8, 16, 32
}PLAYBACK_MODE;

typedef enum _FS_RECORD_TYPE_
{
	FS_RECORD_NONE = 0x0000,		//没有录像
	FS_RECORD_SCHEDULE = 0x0001,		//定时录像
	FS_RECORD_MANUAL = 0x0002,		//手动录像
	ALARM_TYPE_MD = 0x0004,       //移动
	ALARM_TYPE_PD = 0x0008,		//人形
	ALARM_TYPE_VOICE = 0x0010,		//声音
	//后续扩展支持
	ALARM_TYPE_FD = 0x0020,		//人脸
	ALARM_TYPE_CDD = 0x0040,		//宠物检测
	ALARM_TYPE_SENSOR = 0x0080,		//传感器
}FS_REC_TYPE;
//这里有采用位标记 主要考虑到 算法判断可能会有两种同时触发，录像段还未结束，属性重叠的时候，
//rec_type = 0x18  这个表示即有人形和声音触发。

/*
typedef enum {
	ALARM_TYPE_NONE,
	ALARM_TYPE_MD,       //移动
	ALARM_TYPE_PD,		//人形
	ALARM_TYPE_VOICE,   //声音
	ALARM_TYPE_FD,	    //人脸
	ALARM_TYPE_CDD,	    //宠物检测
}ALARM_TYPE;
*/
typedef struct _EXTRA_REC_INFO_
{
	time_t cur_tm;        //当时时间
	int   event_id;       //子事件ID 0：无 1：传感器 2:车牌识别 
	int   record_fps;     //视频帧率
	int   info_len;        //信息长度 
	char  extra_info[256]; //录像段标记TAG
}EXTRA_REC_INFO;

typedef enum _record_status_
{
	RECORD_STATUS_UNUSED = 0,		//未使用
	RECORD_STATUS_USED = 0x01,	//正常使用中（未锁定、未隐藏）
	RECORD_STATUS_LOCK = 0x02,	//被锁定
}REC_STATUS;

//==============================================
// Define data structure
//==============================================
typedef struct _DiskInfo_
{
	int32_t status;					//0 表示掉线　1 表示激活
	int32_t type;					//磁盘接口类型：本地 0 SATA）、1 E_SATA、2 USB， 3 IP_SAN、4 NAS、、等（只读�?
	int32_t property;				//属性：只读、冗余、读写
	int32_t isFormated;				//是否已经格式化
	int32_t diskIndex;				//磁盘编号
	int32_t portType;				//端口类型
	int32_t portNum;				//端口号
	uint32_t   recSpace;		//录像总容量：MB（只读）
	uint32_t   recFreeSpace;	//录像剩余容量：MB（只读）
	uint32_t   recUsedSpace;	//录像使用容量：MB（只读）

	uint32_t   comPartSpace;    //通用盘的空间大小MB 
	uint32_t   comPartFreeSpace;//剩余大小 MB 
	uint32_t   comUsedSpace;    //通用盘使用空间 MB 

	uint32_t   totalSpace;		//磁盘总容量MB
	char       diskName[20];     //设备名称
}DiskInfo;

typedef enum _FS_DATA_PART_TYPE_
{
	FS_PART_COMMON = 0,  //通用普通磁盘
	FS_PART_RECORD = 1,  //录像区 预分配区
	FS_PART_PIC = 2,  //图片区 预分配区
	FS_PART_LOG,    //日志区

}FS_DATA_PART_TYPE;

typedef struct _FS_PART_INFO_
{
	uint8_t       data_type;   // FS_DATA_PART_TYPE   
	uint8_t       is_use_percent; //使用百分比
	union
	{
		uint32_t  disk_percent; //磁盘分区百分比
		uint32_t  part_sz_MB;   //分区大小 单位MB
	};
	uint32_t      blk_MB;        //邓分配文件块大小 单位MB  
	uint32_t      index_blk_sz; //录像区和图片区生效，索引段大小最小2K，缺省值4K
}FS_PART_INFO;

typedef struct _PART_TABLE_
{
	int         num; //分区总数
	FS_PART_INFO* part;
}FS_PART_TABLE;

struct UDevInfo
{
	char mountPoint[64];	//挂载路径
	char deviceText[36];	//设备名称
	uint64_t totalSize;	//Byte
	uint64_t freeSpace;	//Byte
	int32_t udevStatus;			//0-正常挂载,可读写;1-正常挂载,不可读写;2-正常挂载,未格式化;3-正常卸载
};
typedef struct _RECORD_CH_INFO_
{
	uint32_t chManualBIT;
	int32_t    sptChNum;  //支持的通道数
	char   recType[32];//最多支持32通道
}RECORD_CH_INFO;


typedef struct _BACKUP_PARAM_
{
	int32_t     selectMode;			//选择备份模式
	uint16_t	style;				//采用USB, FTP, DISK, DVD, 方式备份
	uint16_t 	fileFormat;			//备份格式, [0 *.asf], [1 *.mp4] [2  bin]
	int32_t     recStartOffset;		//开始的偏移
	int32_t     recNum;				//备份的数目
	char		partPath[128];		//挂载相对路径
}BACKUP_PARAM;

typedef struct _PLAYBACK_INFO_
{
	uint16_t	synchro;		//同步 0, 异步 1
	uint16_t	chnn;			//通道
	uint16_t	status;			//状态PLAYBACK_TYPE
	uint16_t	speed;			//速率 1, 2, 4, 8, 16, 32
	int64_t		time;			//帧时间
	int32_t	    playClientNum;  //
}PLAYBACK_INFO;

typedef enum _DEV_STATUS
{
	DEV_NORMARL = 0,
	DEV_NOREADWRITE = 1,
	DEV_UNFORMATED = 2,
	DEV_UNLOADED = 3,
}DEV_STATUS;

typedef struct _SCHEDULE_REC_
{
	int32_t is_Enable;
	uint64_t scheduleTime[7];
}SCHDULE_REC;

typedef struct _STFS_FBLK_INFO_
{
	char dev[128];  //设备名
	int  part_no;   //分区编号 
	uint32_t  block_idx; //块索引编号
	uint32_t  block_sz;  //块大小
	uint32_t  free_sz;   //剩余大小
}STFS_FBLK_INFO;

//录像段文件信息
#pragma pack(4)
typedef struct _FILE_INFO_
{
	uint32_t    NO;				//文件临时编号
	uint8_t		bCheck;			//是否选中
	uint8_t		channel;		//通道号
	uint8_t		dataSource;		//数据来源	DATA_SOURCE_ID
	uint8_t     timeZone;       //时区
	uint32_t    tmStart;		//开始时间 16+
	uint32_t	tmEnd;			//结束时间
	int64_t	    fileSize;		//录像段大小
	uint32_t	indexNO;		//磁盘上面的索引
	uint8_t		status;			//状态：REC_STATUS
	uint8_t		diskIndex;		//磁盘编号
	uint8_t     recSegIndex;	//录像段编号
	uint8_t     resever;        //保留
	uint16_t	recordType;	   //主录像类型 record_type_
	uint16_t    eventType;     //子录像类型
}FILE_INFO;
#pragma pack()
typedef struct _REC_DAY_
{
	time_t tm_day_start;  // 日期的开始
	time_t tm_day_end;	  // 日期的结束　
}FS_REC_DAY;	//便于快速查看所有录像段

typedef enum _download_type
{
	DOWNLOAD_PLAY = 0,	//远程回放
	DOWNLOAD_BACKUP = 1,	//远程备份
}DOWNLOAD_TYPE;

typedef struct _DOWNLOAD_RECORD_
{
	int32_t	     downloadType;		//DOWNLOAD_TYPE // 0: 远程回放 1:远程备份
	time_t	     startTime;			//起始时间 实时备份
	time_t	     endTime;			//结束时间(在downloadType为DOWNLOAD_PLAY时无效）
	int32_t      ch;                //通道
	int32_t		 recType;			//录像类型
	int32_t		 userBIT;			//用户ID位
}DOWNLOAD_RECORD;

typedef struct _DISK_PERFORMANCE_
{
	int32_t wtSpeed;	//KB/S 会精确到后面两位小数点．
	int32_t rdSpeed;	//KB/S
	int32_t realWtSpd;  //KB/S 实时的写入速度
	int32_t realRdSpd;	//KB/S 实时的读取速度
}DiskPerformance;

typedef struct _REC_SEGMENT_
{
	uint8_t		reserve;		//保留
	uint8_t		channel;		//通道号
	uint8_t		dataSource;		//数据来源	DATA_SOURCE_ID
	uint8_t     timeZone;       //时区2017年5月27日       //uint8_t     reserve;        、、
	int64_t	    fileSize;		//录像段大小

	uint32_t	tmStart;		//开始时间 16+
	uint32_t	tmEnd;			//结束时间

	uint32_t	indexNO;		//磁盘上面的索引
	uint8_t		status;			//状态：RECORD_FILE_STATUS
	uint8_t		diskIndex;		//磁盘编号
	uint8_t     recSegIndex;	//录像段编号
	uint8_t		reserve2;		//保留2

	uint32_t	recordType;		//录像类型 record_type_
	uint32_t	type_ex;		//扩展类型 
}RECORD_SEGMENT, * PRECORD_SEGMENT;

//带标记的信息段
typedef struct _REC_SEGMENT_TAG_
{
	uint32_t    magic;          //标记 "segt"
	uint8_t		haverec;		//保留
	uint8_t		channel;		//通道号
	uint8_t		dataSource;		//数据来源	DATA_SOURCE_ID
	uint8_t     timeZone;       //时区2017年5月27日     
	uint32_t	fileSize;		//录像段大小

	uint32_t	tmStart;		//开始时间 16+
	uint32_t	tmEnd;			//结束时间

	uint32_t	indexNO;		//磁盘上面的索引
	uint8_t		status;			//状态：RECORD_FILE_STATUS
	uint8_t		diskIndex;		//磁盘编号
	uint8_t     recSegIndex;	//录像段编号
	uint8_t		tag_len;		//保留2

	uint32_t	recordType;		//录像类型 record_type_
	uint32_t	type_ex;		//扩展类型 
}RECORD_SEGMENT_TAG, * PRECORD_SEGMENT_TAG;

typedef enum
{
	AUDIO_G726 = 0,
	AUDIO_G711A = 1,
	AUDIO_UNKNOWN,
}AUDIO_TYPE;

#define  LOCAL_CLIENT_ID      0
#define  TELNET_CLINET_ID     1   //网络用户从1开始编号，可以支持到4个
#define  ALL_REC_TYPE         -1


typedef int (*STFS_GetFrame)(unsigned char* buf, uint32_t dataSize, int ch);

#ifdef __cplusplus
extern "C" {
#endif

	//录像模块初始化接口
	int    STFS_Init(StorageConfig cfg);

	//使用Lua脚本来初始化  增强程序的灵活性 2021年12月22日
	int    STFS_Init_bylua(const char* lua);

	//修改缓存接入类型
	int    STFS_Buffer_Change(int* src_type, int num);

	int    STFS_UnInit();

	void    STFS_set_debuglevel(int level);
	//获取录像最大时间
	time_t  STFS_GetRecMaxTime();
	//获取录像最旧时间
	time_t  STFS_GetRecOldTime();

	int   STFS_Get_last_dev_sn(char* device_sn, int sz_len);
	//磁盘管理接口
	//判断当前磁盘是否已经初始化
	int  STFS_DISK_IS_INIT(const char* dev);

	int  STFS_FormatDisk(const char* dev);

	int  STFS_FormatToRecdisk(const char* dev, int blockMB, int compartMB, int useSpaceMB);

	int  STFS_RefreshPartTable(const char* dev);
	StorageSpaceInfo  STFS_GetDiskSpaceInfo();
	//buf 中会用结构体 DiskInfo 填充，返回值 是磁盘的个数
	int  STFS_GetDiskInfo(const char* buf, int bufSize, const char* mnt_dir);
	//添加 磁盘
	int STFS_Add_Disk(const char* dev);
	//删除磁盘
	int STFS_Remove_Disk(const char* dev);
	//设置获取音视频数据回调函数,存储模块内置缓存就可以取消了
	void  STFS_SET_GetFrame_CBK(STFS_GetFrame cbak_funcGetFrame);

	void  STFS_SET_STATUS_CBAK(STORAGE_STATUS_CBAK cbak);

	//录像开始
	int  STFS_RecordStart();

	int  STFS_RecordModeSet(int mode, int allday_rec_chbit);  //mode 0 :全天录像  1:仅报警录像 2: 计划录像， 可磁盘节省空间  allday_rec_chbit :全天录像的通道位，可选择是否录像主码流，还是子码流

	//录像停止
	int  STFS_RecorcStop();

	int  STFS_RecordIsOk();

	//按通道号只停止手动录像
	int  STFS_ManualRecStop(int ch);

	int STFS_RecordSw(int bEnable);
	//按通道位标记一次做到停止
	int  STFS_SET_RECORD_SWITCH(int chSwith);

	//设置是否循环录像
	int  STFS_CycleRec(int bEnable);

	//设置录像计划表
	int  STFS_ScheduleTimeSet(int ch, SCHDULE_REC schduleTime);

	//获取某个通道的计划表
	SCHDULE_REC  STFS_ScheduleTimeGet(int ch);

	int STFS_fopen(const char* dev, int data_type, uint32_t blk_indx, int ch, int streamid, int access_mod);

	int STFS_fwrite(unsigned char* buf, uint32_t size, int fd);

	int STFS_fread(unsigned char* buf, uint32_t size, int fd);

	int STFS_frec_markevent_start(int recType, EXTRA_REC_INFO extraInfo, int fd);

	int STFS_frec_markevent_end(int recType, time_t curTm, int fd);

	int STFS_finfo(int fd, STFS_FBLK_INFO* blk_info);

	int STFS_fseekpos(int fd, uint32_t  offset);

	int STFS_fclose(int fd);

	int STFS_fsync(int fd);

	int STFS_PicSearch(char* fileBuf, int bufSize, time_t tmStart, time_t tmEnd, int32_t chMask);

	//录像其它不同类型的录像使用，在调用此接口时候如果发现录像线程没有开启会重新打开录像线程
	int  STFS_StartRecord(int ch, FS_REC_TYPE recType, int prepare_sec, int recTmSecs, EXTRA_REC_INFO* extraInfo);

	int STFS_RegisterClientID(const char* client_name);

	void STFS_UnRegisterClientID(const char* client_name);
	//内置缓冲,视频及录像缓冲使用
	//此接口附带 pts和编码类型保存 codeType 0 264 1 265
	int  STFS_FifoWriteFrame_pts(unsigned char* buf, uint32_t dataSize, int frameType, int ch, int64_t pts, int codeType);

	//此接口没有区别视频的编码类型 无法区分264和265
	int  STFS_FifoWriteFrame(unsigned char* buf, uint32_t dataSize, int frameType, int ch);

	int  STFS_FifoClearData(int ch);

	int  STFS_FifoReadFrame(unsigned char* buf, uint32_t dataSize, int ch, int clientID);

	//专针对
	int  STFS_FifoReadFrame_live(unsigned char* buf, uint32_t dataSize, int ch, int clientID);

	int  STFS_FifoSeekTime(int64_t startTime, int prepareSecs, int ch, int clientID);
	//读取模拟数据源
	int  STFS_FifoSimulateFrame(unsigned char* buf, uint32_t dataSize, int ch, int clientID);

	int  STFS_FifoGetFrameWater(int ch, int clientID);

	int  STFS_FifoConsumeFrame(int frmSize, int ch, int clientID);

	//环形缓冲信息
	int  STFS_FifoGetDataSize(int ch);

	int  STFS_FIFOGetWarter(int ch);

	int  STFS_GetRecordPercent(int ch);

	int  STFS_GetRecordIndex(int ch);

	int  STFS_GetRecordSn(int ch);
	//回放使用
	//拷贝一帧数据出来

	int  STFS_ReplayFifoReadFrame(unsigned char* buf, int bufSize, int ch, int clientID);

	int  STFS_ReplayFifoClear(int ch, int clientID);
	//回放同步
	int  STFS_ReplaySyncWait(uint64_t frmTm, int mulCH_sync, int ch, int clientID,int no_delay);

	//获取所有通道的状态
	RECORD_CH_INFO  STFS_GetRecordChInfo();

	void  STFS_SetRecordCycle(uint8_t bEnable);

	int  STFS_SetPreareRec(uint8_t bEnable, int nSecs);

	//搜索当月中存在录像的天数
	int  STFS_SearchRecordAllDay(char* recDayBuf, int bufSize, int64_t chBit);

	//返回值 32位 最多31天，刚好可以按位表示哪天存在录像 0x7FFFFFFF
	int  STFS_SearchRecordDayOfMonth(int year, int month, int recType);
	void STFS_SearchMergeTmSet(int secs);
	int  STFS_SearchHistoryRec(unsigned char* fileBuf, int bufSize, time_t tmStart, time_t tmEnd, int32_t ch, int recType, int clientID);
	int  STFS_SearchHistoryRec_byMin(unsigned char* fileBuf, int bufSize, int mins, time_t tmStart, time_t tmEnd, int32_t ch, int recType, int clientID);
	int  STFS_SearchRec(char* fileBuf, int bufSize, time_t tmStart, time_t tmEnd, int32_t chMask, int recType, int storType, int clientID);

	int  STFS_SearchRecByTag(char* tag, int tag_len, char* fileBuf, int bufSize, time_t tmStart, time_t tmEnd, int32_t chMask, int recType, int clientID);

	int  STFS_LockRecord(RECORD_SEGMENT* recSeg);

	int  STFS_UnlockRecord(RECORD_SEGMENT* recSeg);

	//删除录像段
	int  STFS_DeleteRecord(RECORD_SEGMENT* recSeg);

	//过期删除
	int  STFS_DelOldRecord(time_t oldTime);

	//通过时间获取已经搜索过的录像段信息 
	int  STFS_GetSegment(RECORD_SEGMENT* recSeg, time_t tmStart, time_t tmEnd, int ch, int clientID);

	//回放接口,可以支持远程点播, 默认支持4个 ClientID 实际根据产品设备的资源限制定义  0:表示本地用户　　1：远程用户　
	//startTime： 开始时间
	//endTime：  结束时间     指定好回放的时间区域后，
	//seekTime： 定位第一帧时间 

	int STFS_PlaybackBytime(time_t startTime, time_t endTime, time_t seekTime, int channel, int clientID);

	//可以定位到相关的文件,并且会自动结束 
	int STFS_PlaybackToFile(time_t startTime, int channel, int clientID);

	//远程回放一个通道的数据
	//按时间段回放
	int  STFS_TelnetReplay(time_t startTime, time_t endTime, int ch, int clientID);


	//停止回放
	int  STFS_PlaybackStop(int ch, int clientID);
	//回放获取状态
	int  STFS_PlaybackStatus(int ch, time_t playTime, int clientID);

	//回放移动时间
	int  STFS_PlaybackSeekTime(time_t time, int ch, int clientID);

	//切换到下一段录像
	int  STFS_PlaybackSeekNextFile(int ch, int clientID);
	//仅定位当前文件内的时间
	int  STFS_PlaybackFileSeek(int time_pos, int ch, int clientID);
	//回放设置回放模式
	int  STFS_PlaybackSetMode(PLAYBACK_MODE playMod, int speed, int key_step, int ch, int clientID);

	//获取当时回放的时间 UTC,单位ms
	int64_t STFS_PlaybackCurTm(int ch, int clientID);

	//远程下载
	int  STFS_DownloadStart(int clientID, DOWNLOAD_RECORD pDownloadParam);
	//停止下载
	int  STFS_DownloadStop(int clientID, int ch);


	StorageConfig  STFS_GetStorageCfg();

	int  STFS_GetDataPercent();

	//DEBUG专用导出录像文件
	int  STFS_ExportRecordFile(const char* dev, int fileIdx, int fileSize, const char* destFile);
#ifdef _HAVE_BACKUP_
	int  STFS_BackupComFileToMP4(char* filePath, char* destMp4file);
	int  STFS_BackupStart(unsigned char* reclist, int recNum, int	fileFormat, const char* filePath);

	int  STFS_BackupStop();

	int  STFS_BackupAudioParm(AUDIO_TYPE audoType, int samplerate, int audioChannel, int PCMBitSize);
#endif // _HAVE_BACKUP_

	int  STFS_OpenSimulate(const char* file, int chNum);
	int  STFS_GetSimulateRate();

#ifdef __cplusplus
}
#endif
#endif /* _STORAGE_INTERFACE_H */
